package org.iabako.server.dao.business;

import org.iabako.server.dao.JpaDAO;
import org.iabako.server.tools.BundleMessages;
import org.iabako.server.tools.ServerTools;
import org.iabako.shared.entity.business.Expense;
import org.iabako.shared.entity.business.InstallmentsDefinition;
import org.iabako.shared.entity.enumeration.ExpenseCategory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;

import javax.persistence.Query;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

/**
 * Created by jose on 04/11/14.
 */

@Repository("expenseDAO")
public class ExpenseDAO extends JpaDAO<Long, Expense> {

    @Autowired
    BundleMessages messages;

    @Override
    protected String getUniqueNumberVerificationQuery() {
        return "SELECT e.id FROM Expense e WHERE (e.number = :number OR e.number LIKE :numberPrefix) AND e.enterprise IN (:enterprises)";
    }

    public boolean numberIsUsed(String number) {
        List<Long> numberUsedList = getEntityIdsByNumber(getSessionUser().getEnterprise(), number);
        return numberUsedList != null && !numberUsedList.isEmpty();
    }

    @Override
    public String getNextAvailableId() {
        String nextNumber = super.getNextAvailableId();
        boolean numberIsUsed = numberIsUsed(nextNumber);
        if (numberIsUsed && nextNumber.contains("-")) {
            //Then this may be a recurrent Expense
            return getNextCheckedNumber(nextNumber.substring(0, nextNumber.lastIndexOf("-")));
        }
        return nextNumber;
    }

    @Override
    protected String getLastNumberQuery() {
        return "SELECT MAX(e.number) FROM Expense e WHERE e.enterprise IN (:enterprises)";
    }

    public List<String> getAllCustomCategories() {

        String query = "SELECT DISTINCT e.category FROM Expense e WHERE " +
                "e.category NOT IN (:standardCategories) AND e.enterprise IN (:enterprises)";

        List<String> standardCategories = new ArrayList<String>();
        for (ExpenseCategory expenseCategory : ExpenseCategory.values()) {
            standardCategories.add(messages.getLabel(expenseCategory.getLabelKey()));
        }
        return (List<String>) entityManager.createQuery(query).
                setParameter("standardCategories", standardCategories).
                setParameter("enterprises", getSessionUser().getEnterprise().getAllRelatedEnterprises()).
                getResultList();
    }

    public List<String> getCategoriesBySuggestion(String suggestion) {

        String query = "SELECT DISTINCT category FROM Expense WHERE " +
                "category LIKE :suggestion AND enterprise IN (:enterprises) order by category asc";

        return (List<String>) entityManager.createQuery(query).
                setParameter("enterprises", getSessionUser().getEnterprise().getVisibleEnterprisesFinancialData()).
                setParameter("suggestion", "%" + suggestion + "%").
                setMaxResults(10).getResultList();
    }

    public List<InstallmentsDefinition> getExpiredUndefinedInstallments() {
        String query = "SELECT iDef FROM InstallmentsDefinition iDef WHERE iDef IN (SELECT DISTINCT iDef2 FROM Expense e JOIN e.installmentsDefinition iDef2) AND iDef.nextUndefinedInstallment <= :now";
        return (List<InstallmentsDefinition>) entityManager.createQuery(query).setParameter("now", new ServerTools().resetTime(new Date())).getResultList();
    }

    public Expense getLastExpenseByInstallmentsDefinition(InstallmentsDefinition iDef) {
        String query = "SELECT e FROM Expense e WHERE e.installmentsDefinition = :iDef ORDER BY e.paymentDate desc";
        return (Expense) entityManager.createQuery(query).setParameter("iDef", iDef).setMaxResults(1).getSingleResult();
    }

    public Long getCountExpensesByInstallmentsDefinition(InstallmentsDefinition iDef) {
        String query = "SELECT COUNT(e) FROM Expense e WHERE e.installmentsDefinition = :iDef";
        return (Long) entityManager.createQuery(query).setParameter("iDef", iDef).getSingleResult();
    }

    public Double getLastTax() {
        String queryString = "SELECT e.taxPercent FROM Expense e WHERE e.taxPercent IS NOT NULL AND " +
                "e.enterprise IN (:enterprises) order by e.id desc";
        Query query = entityManager.createQuery(queryString);
        query.setMaxResults(1);
        List<Double> result = (List<Double>) query.setParameter("enterprises", getSessionUser().getEnterprise().getAllRelatedEnterprises()).getResultList();
        return result == null || result.isEmpty() ? null : result.get(0);
    }

    public void deleteAttachedObjects(Long id) {
        String query = "DELETE FROM TrackingObject to WHERE to.expense.id = :expenseId";
        entityManager.createQuery(query).setParameter("expenseId", id).executeUpdate();
    }
}
